#include <stdio.h>
#include <string.h>
#include "board_part_opt.h"
#include "bootpara_deal.h"

uint32_t get_bootmode(void)
{
    boot_param_t bootmode;

    if (board_read_data(BOOTMODE_PARAM_ADDR, (uint8_t *)&bootmode, sizeof(boot_param_t)) != SUCCESS) {
        printf("read bootloader param partition err, return default bootmode\n");
        bootmode.param = BOOTPARAM_DEFAULT_BOOTMODE;
    }
    if ((BOOTPARAM_MAGICNUM != bootmode.magic) || (bootmode.param != BOOT_MODE && bootmode.param != DOWN_MODE))
        bootmode.param = BOOTPARAM_DEFAULT_BOOTMODE;

    return bootmode.param;
}

uint32_t get_baudrate(void)
{
    boot_param_t baudrate;

    if (board_read_data(BAUDRATE_PARAM_ADDR, (uint8_t *)&baudrate, sizeof(boot_param_t)) != SUCCESS) {
        printf("read bootloader param partition err, return default baudrate\n");
        baudrate.param = BOOTPARAM_DEFAULT_BAUDRATE;
    }
    if ((BOOTPARAM_MAGICNUM != baudrate.magic) || ((baudrate.param > BOOTPARAM_MAX_BAUDRATE) || (baudrate.param <= BOOTPARAM_MIN_BAUDRATE)))
        baudrate.param = BOOTPARAM_DEFAULT_BAUDRATE;

    return baudrate.param;
}

uint32_t get_app_state(void)
{
    boot_param_t app_state;
    
    if (board_read_data(APP_STATE_PARAM_ADDR, (uint8_t *)&app_state, sizeof(boot_param_t)) != SUCCESS) {
        app_state.param = BOOTPARAM_DEFAULT_APP_STATE;
        printf("read bootloader param partition err, return default app state\n");
    }
    if ((BOOTPARAM_MAGICNUM != app_state.magic) || (app_state.param != APP_VALID && app_state.param != APP_INVALID))
        app_state.param = BOOTPARAM_DEFAULT_APP_STATE;

    return app_state.param;
}

uint32_t get_boot_state(void)
{
    boot_param_t boot_state;
    
    if (board_read_data(BOOT_STATE_PARAM_ADDR, (uint8_t *)&boot_state, sizeof(boot_param_t)) != SUCCESS) {
        boot_state.param = BOOTPARAM_DEFAULT_APP_STATE;
        printf("read bootloader param partition err, return default boot state\n");
    }
    if ((BOOTPARAM_MAGICNUM != boot_state.magic) || (boot_state.param != FIRST_BOOT && boot_state.param != NON_FIRST_BOOT))
        boot_state.param = BOOTPARAM_DEFAULT_BOOT_STATE;

    return boot_state.param;
}

uint32_t get_boot_part(void)
{
    boot_param_t boot_part;
    
    if (board_read_data(BOOT_PART_PARAM_ADDR, (uint8_t *)&boot_part, sizeof(boot_param_t)) != SUCCESS) {
        boot_part.param = BOOTPARAM_DEFAULT_BOOT_PART;
        printf("read bootloader param partition err, return default boot part\n");
    }
    if ((BOOTPARAM_MAGICNUM != boot_part.magic) || (boot_part.param != APP_PART && boot_part.param != OTA_PART))
        boot_part.param = BOOTPARAM_DEFAULT_BOOT_PART;

    return boot_part.param;
}

uint32_t get_powerOff_state(void)
{
    boot_param_t boot_part;
    if (board_read_data(POWER_OFF_PRESTATE_PARAM_ADDR, (uint8_t *)&boot_part, sizeof(boot_param_t)) != SUCCESS) {
        boot_part.param = BOOTPARAM_DEFAULT_POWER_OFF_PRE_STATA;
        printf("read bootloader param partition err, return default powerOff part\n");
    }
	if ((BOOTPARAM_MAGICNUM != boot_part.magic) || ((boot_part.param >= POWER_OFF_MAX_NUM_STATES) || (boot_part.param < FIRST_POWER_ON)))
        boot_part.param = BOOTPARAM_DEFAULT_POWER_OFF_PRE_STATA;

    return boot_part.param;
}

int set_powerOff_state(uint32_t state)
{
    boot_param_list_t boot_param_list;

    if (board_read_data(BOOTLOADER_PARAM_PARTITION_START, (uint8_t *)&boot_param_list, sizeof(boot_param_list_t)) != SUCCESS) {
        printf("read bootloader params err\n");
        return FAILURE;
    }
    if ((state >= POWER_OFF_MAX_NUM_STATES) || (state < FIRST_POWER_ON)) {
        printf("input powerOffPreState %d invalid\n",state);
        return FAILURE;
    }
    boot_param_list.powerOffState_part_para.magic = BOOTPARAM_MAGICNUM;
    boot_param_list.powerOffState_part_para.param = state;
#ifdef CONFIG_AOS_FATFS_SUPPORT_FLASH    
    if (board_erase(BOOTLOADER_PARAM_PARTITION_START,  BOOTLOADER_PARAM_PARTITION_SIZE) != SUCCESS) {
        printf("erase bootloader param partition err\n");
        return FAILURE;
    }
#endif    
    if (board_write_data(BOOTLOADER_PARAM_PARTITION_START,  (uint8_t *)&boot_param_list, sizeof(boot_param_list_t)) != SUCCESS) {
        printf("write bootloader param partition err\n");
        return FAILURE;
    }

    return SUCCESS;
}

int set_baudrate(uint32_t baudrate)
{
    boot_param_list_t boot_param_list;

    if (board_read_data(BOOTLOADER_PARAM_PARTITION_START, (uint8_t *)&boot_param_list, sizeof(boot_param_list_t)) != SUCCESS) {
        printf("read bootloader params err\n");
        return FAILURE;
    }
    if ((baudrate > BOOTPARAM_MAX_BAUDRATE) || (baudrate <= BOOTPARAM_MIN_BAUDRATE)) {
        printf("input baudrate invalid\n");
        return FAILURE;
    }
    boot_param_list.baudrate_para.magic = BOOTPARAM_MAGICNUM;
    boot_param_list.baudrate_para.param = baudrate;
#ifdef CONFIG_AOS_FATFS_SUPPORT_FLASH    
    if (board_erase(BOOTLOADER_PARAM_PARTITION_START,  BOOTLOADER_PARAM_PARTITION_SIZE) != SUCCESS) {
        printf("erase bootloader param partition err\n");
        return FAILURE;
    }
#endif    
    if (board_write_data(BOOTLOADER_PARAM_PARTITION_START,  (uint8_t *)&boot_param_list, sizeof(boot_param_list_t)) != SUCCESS) {
        printf("write bootloader param partition err\n");
        return FAILURE;
    }

    return SUCCESS;
}
                    
int set_bootmode(uint8_t bootmode)
{
    boot_param_list_t boot_param_list;

    if (board_read_data(BOOTLOADER_PARAM_PARTITION_START, (uint8_t *)&boot_param_list, sizeof(boot_param_list_t)) != SUCCESS) {
        printf("read bootloader params err\n");
        return FAILURE;
    }

    if (BOOT_MODE_NUM == bootmode)
        boot_param_list.bootmode_para.param = BOOT_MODE;
    else if(DOWN_MODE_NUM == bootmode)
        boot_param_list.bootmode_para.param = DOWN_MODE;
    else {
        printf("input bootmode invalid\n");
        return FAILURE;
    }      
    boot_param_list.bootmode_para.magic = BOOTPARAM_MAGICNUM;
#ifdef CONFIG_AOS_FATFS_SUPPORT_FLASH    
    if (board_erase(BOOTLOADER_PARAM_PARTITION_START,  BOOTLOADER_PARAM_PARTITION_SIZE) != SUCCESS) {
        printf("erase bootloader param partition err\n");
        return FAILURE;
    }
#endif    
    if (board_write_data(BOOTLOADER_PARAM_PARTITION_START,  (uint8_t *)&boot_param_list, sizeof(boot_param_list_t)) != SUCCESS) {
        printf("write bootloader param partition err\n");
        return FAILURE;
    }

    return SUCCESS;
}

int set_app_state(uint8_t app_state)
{
    boot_param_list_t boot_param_list;

    if (board_read_data(BOOTLOADER_PARAM_PARTITION_START, (uint8_t *)&boot_param_list, sizeof(boot_param_list_t)) != SUCCESS) {
        printf("read bootloader params err\n");
        return FAILURE;
    }

    if (APP_VALID_NUM == app_state)
        boot_param_list.app_state_para.param = APP_VALID;
    else if(APP_INVALID_NUM == app_state)
        boot_param_list.app_state_para.param = APP_INVALID;
    else {
        printf("input app_state invalid\n");
        return FAILURE;
    }      
    boot_param_list.app_state_para.magic = BOOTPARAM_MAGICNUM;
#ifdef CONFIG_AOS_FATFS_SUPPORT_FLASH    
    if (board_erase(BOOTLOADER_PARAM_PARTITION_START,  BOOTLOADER_PARAM_PARTITION_SIZE) != SUCCESS) {
        printf("erase bootloader param partition err\n");
        return FAILURE;
    }
#endif    
    if (board_write_data(BOOTLOADER_PARAM_PARTITION_START,  (uint8_t *)&boot_param_list, sizeof(boot_param_list_t)) != SUCCESS) {
        printf("write bootloader param partition err\n");
        return FAILURE;
    }

    return SUCCESS;
}

int set_boot_state(uint8_t boot_state)
{
    boot_param_list_t boot_param_list;

    if (board_read_data(BOOTLOADER_PARAM_PARTITION_START, (uint8_t *)&boot_param_list, sizeof(boot_param_list_t)) != SUCCESS) {
        printf("read bootloader params err\n");
        return FAILURE;
    }

    if (FIRST_BOOT_NUM == boot_state)
        boot_param_list.boot_state_para.param = FIRST_BOOT;
    else if(NON_FIRST_BOOT_NUM == boot_state)
        boot_param_list.boot_state_para.param = NON_FIRST_BOOT;
    else {
        printf("input boot_state invalid\n");
        return FAILURE;
    }
    boot_param_list.boot_state_para.magic = BOOTPARAM_MAGICNUM;
#ifdef CONFIG_AOS_FATFS_SUPPORT_FLASH    
    if (board_erase(BOOTLOADER_PARAM_PARTITION_START,  BOOTLOADER_PARAM_PARTITION_SIZE) != SUCCESS) {
        printf("erase bootloader param partition err\n");
        return FAILURE;
    }
#endif    
    if (board_write_data(BOOTLOADER_PARAM_PARTITION_START,  (uint8_t *)&boot_param_list, sizeof(boot_param_list_t)) != SUCCESS) {
        printf("write bootloader param partition err\n");
        return FAILURE;
    }

    return SUCCESS;
}

int set_boot_part(uint8_t boot_part)
{
    boot_param_list_t boot_param_list;

    if (board_read_data(BOOTLOADER_PARAM_PARTITION_START, (uint8_t *)&boot_param_list, sizeof(boot_param_list_t)) != SUCCESS) {
        printf("read bootloader params err\n");
        return FAILURE;
    }

    if (APP_PART_NUM == boot_part)
        boot_param_list.boot_part_para.param = APP_PART;
    else if(OTA_PART_NUM == boot_part)
        boot_param_list.boot_part_para.param = OTA_PART;
    else {
        printf("input boot_part invalid\n");
        return FAILURE;
    }
    boot_param_list.boot_part_para.magic = BOOTPARAM_MAGICNUM;
#ifdef CONFIG_AOS_FATFS_SUPPORT_FLASH        
    if (board_erase(BOOTLOADER_PARAM_PARTITION_START,  BOOTLOADER_PARAM_PARTITION_SIZE) != SUCCESS) {
        printf("erase bootloader param partition err\n");
        return FAILURE;
    }
#endif    
    if (board_write_data(BOOTLOADER_PARAM_PARTITION_START,  (uint8_t *)&boot_param_list, sizeof(boot_param_list_t)) != SUCCESS) {
        printf("write bootloader param partition err\n");
        return FAILURE;
    }

    return SUCCESS;
}

int set_bootpara_list(boot_param_cfg_list_t *boot_param_cfg_list)
{
    boot_param_list_t boot_param_list;

    if (board_read_data(BOOTLOADER_PARAM_PARTITION_START, (uint8_t *)&boot_param_list, sizeof(boot_param_list_t)) != SUCCESS) {
        printf("read bootloader params err\n");
        return FAILURE;
    }

    if (BOOT_PARA_NEED_SET == boot_param_cfg_list->app_state_para_cfg.flag) {
        if (boot_param_cfg_list->app_state_para_cfg.para != APP_VALID &&
            boot_param_cfg_list->app_state_para_cfg.para != APP_INVALID) {
            printf("input app_state invalid\n");
            return FAILURE;
        }
        boot_param_list.app_state_para.magic = BOOTPARAM_MAGICNUM;
        boot_param_list.app_state_para.param = boot_param_cfg_list->app_state_para_cfg.para;
    }
    if (BOOT_PARA_NEED_SET == boot_param_cfg_list->boot_state_para_cfg.flag) {
        if (boot_param_cfg_list->boot_state_para_cfg.para != FIRST_BOOT &&
            boot_param_cfg_list->boot_state_para_cfg.para != NON_FIRST_BOOT) {
            printf("input boot_state invalid\n");
            return FAILURE;
        }
        boot_param_list.boot_state_para.magic = BOOTPARAM_MAGICNUM;
        boot_param_list.boot_state_para.param = boot_param_cfg_list->boot_state_para_cfg.para;
    }
    if (BOOT_PARA_NEED_SET == boot_param_cfg_list->baudrate_para_cfg.flag) {
        if (boot_param_cfg_list->baudrate_para_cfg.para > BOOTPARAM_MAX_BAUDRATE) {
            printf("input baudrate invalid\n");
            return FAILURE;
        }      
        boot_param_list.baudrate_para.magic = BOOTPARAM_MAGICNUM;
        boot_param_list.baudrate_para.param = boot_param_cfg_list->baudrate_para_cfg.para;
    }
    if (BOOT_PARA_NEED_SET == boot_param_cfg_list->bootmode_para_cfg.flag) {
        if (boot_param_cfg_list->bootmode_para_cfg.para != DOWN_MODE &&
            boot_param_cfg_list->bootmode_para_cfg.para != BOOT_MODE) {
            printf("input bootmode invalid\n");
            return FAILURE;
        }
        boot_param_list.bootmode_para.magic = BOOTPARAM_MAGICNUM;
        boot_param_list.bootmode_para.param = boot_param_cfg_list->bootmode_para_cfg.para;
    }
    if (BOOT_PARA_NEED_SET == boot_param_cfg_list->boot_part_para_cfg.flag) {
        if (boot_param_cfg_list->boot_part_para_cfg.para != APP_PART &&
            boot_param_cfg_list->boot_part_para_cfg.para != OTA_PART) {
            printf("input boot_part invalid\n");
            return FAILURE;
        }
        boot_param_list.boot_part_para.magic = BOOTPARAM_MAGICNUM;
        boot_param_list.boot_part_para.param = boot_param_cfg_list->boot_part_para_cfg.para;
    }
#ifdef CONFIG_AOS_FATFS_SUPPORT_FLASH    
    if (board_erase(BOOTLOADER_PARAM_PARTITION_START,  BOOTLOADER_PARAM_PARTITION_SIZE) != SUCCESS) {
        printf("erase bootloader param partition err\n");
        return FAILURE;
    }
#endif    
    if (board_write_data(BOOTLOADER_PARAM_PARTITION_START,  (uint8_t *)&boot_param_list, sizeof(boot_param_list_t)) != SUCCESS) {
        printf("write bootloader param partition err\n");
        return FAILURE;
    }

    return SUCCESS;
}

int is_firsttime_booting(void)
{
    return (get_boot_state() == FIRST_BOOT ? 1 : 0);
}

int first_time_bootup(void)
{
    int ret = SUCCESS;
    boot_param_cfg_list_t boot_param_cfg_list;

    if (is_firsttime_booting()) {
        memset(&boot_param_cfg_list, 0, sizeof(boot_param_cfg_list_t));
        boot_param_cfg_list.app_state_para_cfg.flag = BOOT_PARA_NEED_SET;
        boot_param_cfg_list.app_state_para_cfg.para = APP_VALID;
        boot_param_cfg_list.boot_state_para_cfg.flag = BOOT_PARA_NEED_SET;
        boot_param_cfg_list.boot_state_para_cfg.para = NON_FIRST_BOOT;
        ret = set_bootpara_list(&boot_param_cfg_list);
    }

    return ret;
}

uint32_t get_update_part_index(void)
{
    return (get_boot_part() == APP_PART ? HAL_PARTITION_OTA_TEMP : HAL_PARTITION_APPLICATION);
}

uint32_t get_boot_part_index(void)
{
    return (get_boot_part() == APP_PART ? HAL_PARTITION_APPLICATION : HAL_PARTITION_OTA_TEMP);
}

int setup_bootpara_afterburn(uint32_t boot_base)
{
    int ret = SUCCESS;
    boot_param_cfg_list_t boot_param_cfg_list;

    memset(&boot_param_cfg_list, 0, sizeof(boot_param_cfg_list_t));
    boot_param_cfg_list.app_state_para_cfg.flag = BOOT_PARA_NEED_SET;
    boot_param_cfg_list.app_state_para_cfg.para = APP_VALID;
    boot_param_cfg_list.bootmode_para_cfg.flag = BOOT_PARA_NEED_SET;
    boot_param_cfg_list.bootmode_para_cfg.para = BOOT_MODE;
    boot_param_cfg_list.boot_state_para_cfg.flag = BOOT_PARA_NEED_SET;
    boot_param_cfg_list.boot_state_para_cfg.para = FIRST_BOOT;
    boot_param_cfg_list.boot_part_para_cfg.flag = BOOT_PARA_NEED_SET;
    boot_param_cfg_list.boot_part_para_cfg.para = boot_base == APP_PART ? OTA_PART : APP_PART;
    ret = set_bootpara_list(&boot_param_cfg_list);

    return ret;
}
